package webx.json;

import stdx.Utils;
import java.util.Collection;
import java.lang.reflect.Field;

public class JsonObject{
	String val = null;
	com.google.gson.JsonArray array = null;
	com.google.gson.JsonObject json = null;

	public JsonObject(){
	}
	public JsonObject(String msg){
		try{
			this.parse(msg);
		}
		catch(Exception e){
		}
	}
	public JsonObject(com.google.gson.JsonObject obj){
		this.json = obj;
	}
	public JsonObject(com.google.gson.JsonElement elem){
		if (elem.isJsonObject()){
			this.json = elem.getAsJsonObject();
		}
		else if (elem.isJsonArray()){
			this.array = elem.getAsJsonArray();
		}
		else if (elem.isJsonPrimitive()){
			this.val = elem.getAsString();
		}
	}

	public String toString(){
		if (val != null) return val;
		if (json != null) return json.toString();
		if (array != null) return array.toString();
		return "";
	}
	public <T> T toObject(Class<T> clazz) throws InstantiationException, IllegalAccessException{
	    T res = clazz.newInstance();

	    return res;
    }
	public void parse(String msg) throws Exception{
		val = null;
		json = null;
		array = null;

		com.google.gson.JsonElement elem = new com.google.gson.JsonParser().parse(msg);

		if (elem.isJsonPrimitive()) val = elem.getAsString();
		else if (elem.isJsonArray()) array = (com.google.gson.JsonArray)(elem);
		else if (elem.isJsonObject()) json = (com.google.gson.JsonObject)(elem);
	}

	public int size(){
		return array.size();
	}
	public boolean has(int idx){
		return array != null && array.size() > idx;
	}
	public boolean has(String key){
		return json != null && json.has(key);
	}
	public JsonObject get(int idx){
		if (array == null || idx >= array.size()) return null;
		return new JsonObject(array.get(idx));
	}
	public JsonObject get(String key){
		return has(key) ? new JsonObject(json.get(key)) : null;
	}

	public boolean isNull(){
		return val == null && json == null && array == null;
	}
	public boolean isValue(){
		return val != null;
	}
	public boolean isArray(){
		return array != null;
	}
	public boolean isObject(){
		return json != null;
	}
	public boolean isNull(int idx){
		return has(idx) ? get(idx).isNull() : true;
	}
	public boolean isValue(int idx){
		return has(idx) ? get(idx).isValue() : false;
	}
	public boolean isArray(int idx){
		return has(idx) ? get(idx).isArray() : false;
	}
	public boolean isObject(int idx){
		return has(idx) ? get(idx).isObject() : false;
	}
	public boolean isNull(String key){
		return has(key) ? json.get(key).isJsonNull() : true;
	}
	public boolean isValue(String key){
		return has(key) ? json.get(key).isJsonPrimitive() : false;
	}
	public boolean isArray(String key){
		return has(key) ? json.get(key).isJsonArray() : false;
	}
	public boolean isObject(String key){
		return has(key) ? json.get(key).isJsonObject() : false;
	}

	public int asInt(int idx){
		String val = asString(idx);
		if (val == null || val.isEmpty()) return 0;
		return Integer.parseInt(val);
	}
    public String asString(int idx){
        JsonObject obj = get(idx);
        if (obj == null) return null;
        if (obj.isValue()) return obj.toString();
        return null;
    }
	public double asDouble(int idx){
		String val = asString(idx);
		if (val == null || val.isEmpty()) return 0;
		return Double.parseDouble(val);
	}

	public int asInt(String key){
		String val = asString(key);
		if (val == null || val.isEmpty()) return 0;
		return Integer.parseInt(val);
	}
    public String asString(String key){
        if (has(key)){
            com.google.gson.JsonElement tmp = json.get(key);
            if (tmp.isJsonPrimitive()) return tmp.getAsString();
        }
        return null;
    }
	public double asDouble(String key){
		String val = asString(key);
		if (val == null || val.isEmpty()) return 0;
		return Double.parseDouble(val);
	}

    public void addNull(){
        if (isArray()) array.add(null);
    }
    public void add(String val){
        array.add(new com.google.gson.JsonParser().parse(String.valueOf(val)));
    }
    public void add(Number val){
        array.add(new com.google.gson.JsonParser().parse(String.valueOf(val)));
    }
    public void add(Boolean val){
        array.add(new com.google.gson.JsonParser().parse(String.valueOf(val)));
    }
    public void add(Character val){
        array.add(new com.google.gson.JsonParser().parse(String.valueOf(val)));
    }
	public void add(JsonObject val){
		if (isArray()){
			if (val.isArray()) array.add(val.array);
			else if (val.isObject()) array.add(val.json);
			else if (val.isValue()) add(val.val);
		}
	}
	public void remove(String key){
		if (has(key)) json.remove(key);
	}
    public JsonObject addNull(String key){
        json.add(key, null);
        return get(key);
    }
	public JsonObject addObject(String key){
		JsonObject item = new JsonObject(new com.google.gson.JsonParser().parse("{}"));
		json.add(key, item.json);
		return item;
	}
	public JsonObject addArray(String key){
		JsonObject item = new JsonObject(new com.google.gson.JsonParser().parse("[]"));
		json.add(key, item.array);
		return item;
	}

    public void put(String key, String val){
	    json.addProperty(key, val);
    }
    public void put(String key, Number val){
        json.addProperty(key, val);
    }
    public void put(String key, Boolean val){
        json.addProperty(key, val);
    }
    public void put(String key, Character val){
        json.addProperty(key, val);
    }
    public JsonObject put(String key, JsonObject val){
		if (json.has(key)) json.remove(key);
		if (val.isArray()) json.add(key, val.array);
		else if (val.isObject()) json.add(key, val.json);
		else if (val.isValue()) put(key, val.val);
		return new JsonObject(json.get(key));
	}

    public static void InitObject(Object obj, JsonObject json) throws IllegalAccessException{
        if (json.isNull()) return;

        Field[] fields = obj.getClass().getDeclaredFields();

        for (Field field : fields) Utils.InitFieldValue(field, obj, json.asString(field.getName()));
    }
    public static JsonObject FromObject(Object obj) throws IllegalAccessException{
	    if (obj == null) return new JsonObject();

	    if (obj instanceof Collection){
            Collection vec = (Collection)(obj);
            JsonObject json = new JsonObject("[]");

	        for (Object item : vec){
	            if (item == null){
	                json.addNull();
                }
                else if (item instanceof String){
                    json.add((String)(item));
                }
                else if (item instanceof Integer){
                    json.add((Integer)(item));
                }
                else if (item instanceof Double){
                    json.add((Double)(item));
                }
                else if (item instanceof Boolean){
                    json.add((Boolean)(item));
                }
                else if (item instanceof Long){
                    json.add((Long)(item));
                }
                else if (item instanceof Short){
                    json.add((Short)(item));
                }
                else if (item instanceof Float){
                    json.add((Float)(item));
                }
                else if (item instanceof Character){
                    json.add(String.valueOf(item));
                }
                else{
                    json.add(FromObject(item));
                }
            }

            return json;
        }
        else {
            JsonObject json = new JsonObject("{}");
            Field[] fields = obj.getClass().getDeclaredFields();

            for (Field field : fields) {
                String name = field.getName();
                String type = field.getGenericType().toString();

                field.setAccessible(true);

                Object item = field.get(obj);

                if (item == null){
                    json.addNull(name);
                }
                else if (item instanceof String){
                    json.put(name, (String)(item));
                }
                else if (item instanceof Integer){
                    json.put(name, (Integer)(item));
                }
                else if (item instanceof Double){
                    json.put(name, (Double)(item));
                }
                else if (item instanceof Boolean){
                    json.put(name, (Boolean)(item));
                }
                else if (item instanceof Long){
                    json.put(name, (Long)(item));
                }
                else if (item instanceof Short){
                    json.put(name, (Short)(item));
                }
                else if (item instanceof Float){
                    json.put(name, (Float)(item));
                }
                else if (item instanceof Character){
                    json.put(name, String.valueOf(item));
				}
				else{
					json.put(name, FromObject(item));
				}
            }

            return json;
        }
    }
}
